<template>
    <div>
        <ShapeToolber />
        <div class="grids">
            <div class="left">
                <div class="editor" id="editor" :style="editorStyle" @mousedown="handleMouseDown" @click="gridClick">
                    <ShapeGrid />
                    <Shape v-for="(item, index) in componentData" 
                        :key="index" 
                        :index="index" 
                        :defaultStyle="item.style" 
                        :element="item" 
                        :active="item === curComponent"
                        :style="getShapeStyle(item.style)">
                    </Shape>

                    <ShapeMarkLine />
                    <!-- <ShapeArea :start="start" :width="width" :height="height" v-show="isShowArea" /> -->
                </div>
            </div>
            <div class="right">
                <ShapeEdit></ShapeEdit>
            </div>
        </div>
    </div>
</template>

<script>
import { mapState } from 'vuex';
import Shape from './editor/shape.vue';
import ShapeGrid from './editor/grid.vue';
// import ShapeArea from './editor/area.vue';
import ShapeMarkLine from './editor/markLine.vue';
import ShapeEdit from './shapeEdit.vue';
import ShapeToolber from './toolber.vue';
import { getComponentRotatedStyle } from '@/utils/grids/style';

export default {
    components: {
        Shape,
        ShapeGrid,
        // ShapeArea,
        ShapeMarkLine,
        ShapeEdit,
        ShapeToolber,
    },
    data() {
        return {
            start: { // 选中区域的起点
                x: 0,
                y: 0,
            },
            width: 0,
            height: 0,
            isShowArea: false,
            editor: null
        }
    },
    computed: {
        ...mapState({
            componentData: state => state.grids.componentData,
            curComponent: state => state.grids.curComponent,
            canvasStyleData: state => state.grids.canvasStyleData,
        }),
        editorStyle() {
            const { width, height, scale } = this.canvasStyleData;
            return {
                width: `${width * scale / 100}px`,
                height: `${height * scale / 100}px`,
            }
        }
    },
    mounted() {
        // 获取编辑器元素
        this.editor = document.querySelector('#editor')
        
        this.$bus.$on('hideArea', () => {
            this.hideArea()
        })
    },
    methods: {
        getShapeStyle(style) {
            const result = {};
            ['width', 'height', 'top', 'left', 'rotate', 'backgroundColor', 
                'borderTop', 'borderTopColor', 'borderRight', 'borderRightColor', 'borderBottom', 'borderBottomColor', 'borderLeft', 'borderLeftColor',
            ].forEach(attr => {
                if (['width', 'height', 'top', 'left'].indexOf(attr) != -1) {
                    result[attr] = style[attr] + 'px'
                } else if(attr === 'rotate') {
                    result.transform = 'rotate(' + style[attr] + 'deg)'
                } else if(['borderTop', 'borderRight', 'borderBottom', 'borderLeft'].indexOf(attr) != -1) {
                    result[attr] = `${style[attr]}px solid`
                } else {
                    result[attr] = style[attr]
                }
            })
            return result
        },
        hideArea() {
            this.isShowArea = 0
            this.width = 0
            this.height = 0
        },
        gridClick(e) {
            this.$store.dispatch('setCurComponent', {
                component: null,
                index: null
            })
        },
        handleMouseDown(e) {
            // 如果没有选中组件 在画布上点击时需要调用 e.preventDefault() 防止触发 drop 事件
            if (!this.curComponent) {
                e.preventDefault()
            }
            
            this.hideArea()

            // 获取编辑器的位移信息，每次点击时都需要获取一次。主要是为了方便开发时调试用。
            const rectInfo = this.editor.getBoundingClientRect()
            this.editorX = rectInfo.x
            this.editorY = rectInfo.y
        
            const startX = e.clientX
            const startY = e.clientY
            this.start.x = startX - this.editorX
            this.start.y = startY - this.editorY
            // 展示选中区域
            this.isShowArea = true
            
            const move = (moveEvent) => {
                this.width = Math.abs(moveEvent.clientX - startX)
                this.height = Math.abs(moveEvent.clientY - startY)
                if (moveEvent.clientX < startX) {
                    this.start.x = moveEvent.clientX - this.editorX
                }

                if (moveEvent.clientY < startY) {
                    this.start.y = moveEvent.clientY - this.editorY
                }
            }

            const up = (e) => {
                document.removeEventListener('mousemove', move)
                document.removeEventListener('mouseup', up)

                if (e.clientX == startX && e.clientY == startY) {
                    this.hideArea()
                    return
                }

                this.createGroup()
            }

            document.addEventListener('mousemove', move)
            document.addEventListener('mouseup', up)
        },
        createGroup() {
            // 获取选中区域的组件数据
            const areaData = this.getSelectArea()
            if (areaData.length <= 1) {
                this.hideArea()
                return
            }
            
            // 根据选中区域和区域中每个组件的位移信息来创建 Group 组件
            // 要遍历选择区域的每个组件，获取它们的 left top right bottom 信息来进行比较
            let top = Infinity, left = Infinity
            let right = -Infinity, bottom = -Infinity
            areaData.forEach(component => {
                let style = {}
                if (component.component == 'Group') {
                    component.propValue.forEach(item => {
                        const rectInfo = document.querySelector(`#component${item.id}`).getBoundingClientRect()
                        style.left = rectInfo.left - this.editorX
                        style.top = rectInfo.top - this.editorY
                        style.right = rectInfo.right - this.editorX
                        style.bottom = rectInfo.bottom - this.editorY

                        if (style.left < left) left = style.left
                        if (style.top < top) top = style.top
                        if (style.right > right) right = style.right
                        if (style.bottom > bottom) bottom = style.bottom
                    })
                } else {
                    style = getComponentRotatedStyle(component.style)
                }

                if (style.left < left) left = style.left
                if (style.top < top) top = style.top
                if (style.right > right) right = style.right
                if (style.bottom > bottom) bottom = style.bottom
            })

            this.start.x = left
            this.start.y = top
            this.width = right - left
            this.height = bottom - top

            // 设置选中区域位移大小信息和区域内的组件数据
            this.$store.dispatch('setAreaData', {
                style: {
                    left,
                    top,
                    width: this.width,
                    height: this.height,
                },
                components: areaData,
            })
        },
        getSelectArea() {
            const result = []
            // 区域起点坐标
            const { x, y } = this.start
            // 计算所有的组件数据，判断是否在选中区域内
            this.componentData.forEach(component => {
                if (component.isLock) return

                const { left, top, width, height } = component.style
                if (x <= left && y <= top && (left + width <= x + this.width) && (top + height <= y + this.height)) {
                    result.push(component)
                }
            })

            // 返回在选中区域内的所有组件
            return result
        },

    }
}
</script>

<style lang="scss" scoped>
.grids {
    position: relative;
    .left {
        height: 100%;
        overflow: auto;
        background: #F5F5F5;
        margin-right: 260px;
    }

    .editor{
        position: relative;
    }

    .right {
        position: absolute;
        top: 0;
        right: 0;
        height: 100%;
        border-left: solid 1px #DCDFE6;
        width: 260px;
        box-sizing: border-box;
        padding: 10px;
        z-index: 10;
        background: #FFFFFF;
    }
}
</style>